PHASE 2 · 路由器解剖

2.2OpenWRT 架构全景

UCI、netifd,与配置生效之路

2.1 你认全了路由器上的进程,并看到它们被 procd 管理、通过 ubus 通信。这章补上最后一块拼图:这些进程从哪读配置、配置怎么变成内核里真实的接口和规则。答案的核心是 UCI——OpenWRT 把所有配置统一成一种格式、一套文件、一个命令。理解了"UCI(配置)→ 守护进程(执行)→ 内核(生效)"这条链,你就掌握了 OpenWRT 的全貌,也就知道该去哪改、改了怎么生效。

一句话定义

OpenWRT 的架构 = 统一配置(UCI)+ 一组把配置翻译成实际行为的守护进程+ procd/ubus 的进程管理与通信;所有配置集中在 /etc/config/,由各进程读取并落到内核或服务。

1架构一张图:配置→执行→内核

OpenWRT 是三层:上面是统一配置(UCI),中间是把配置翻译成行为的守护进程,下面是内核机制。每个子系统都是一条竖直的流水线:一个配置文件 → 一个守护进程读它 → 落到内核 / 服务。

网络
/etc/config/
network
netifd
接口 · 路由
(netlink)
防火墙
/etc/config/
firewall
fw4
nftables
DHCP / DNS
/etc/config/
dhcp
dnsmasq
odhcpd
DHCP · DNS
服务
WiFi
/etc/config/
wireless
netifd →
hostapd
WiFi
(nl80211)
横向贯穿:procd 管着这些进程的生命周期 · ubus 让它们互相通信
UCI 配置层 守护进程(执行) 内核 / 服务(生效)

读这张图:每列是一个子系统的完整链路,格式统一的 UCI 文件在最上,守护进程读它、翻译成 Phase 1 的内核状态。LuCI 不是独立的一层——它只是"配置层的图形前端":你在网页上点的每一下,改的还是 UCI、调的还是 ubus。这就是全貌。

2UCI:统一配置系统

传统 Linux 每个服务各有各的配置格式(dnsmasq 一套、防火墙一套、hostapd 一套……)。OpenWRT 用 UCI(Unified Configuration Interface)把它们统一——你只学一种语法,就能配网络、防火墙、DHCP、WiFi。以 /etc/config/network 为例:

/etc/config/network
config interface 'lan'        # 一个 section:类型 interface,名叫 lan
    option device 'br-lan'    # option:单值
    option proto 'static'
    option ipaddr '192.168.1.1'
    option netmask '255.255.255.0'
    list dns '1.1.1.1'        # list:多值

三个关键词:config(定义一个配置节 section)、option(单值)、list(多值)。所有 /etc/config/* 都是这套语法。改配置有三条路,殊途同归、最终都改 UCI:直接编辑文件、用 uci 命令、或 LuCI 点一点。

bash · uci
uci show network                          # 看整个 network 配置
uci get network.lan.ipaddr                # 读一个值
uci set network.lan.ipaddr='192.168.1.2'  # 改(先写进暂存)
uci commit network                        # 提交到 /etc/config/network
类比:UCI 是一个统一配置数据库 + 它的增删改查 API

config / option / list 就是"表 / 字段 / 多值字段";uci set/get/commit 是增删改查;/etc/config/* 是持久化存储。各守护进程从这个统一库读自己那部分。改配置分两步(set 写暂存 → commit 落盘)也像事务。但记住:UCI 只是"配置的单一真相来源",改了还没生效——得让对应进程重读(第 4 节)。

3netifd:配置变成接口和路由

netifd 读 /etc/config/network,把里面的 interface 配置翻译成 Phase 1 那些真实的接口、地址、路由。它引入一个关键抽象:逻辑接口(interface) vs 物理设备(device)

  • UCI 里一个 config interface 'lan' 是个逻辑接口:它绑定一个 device(如 br-lan)、指定 proto、地址等。
  • netifd 读这段,去干 Phase 1 的活:把 device 建好 / 配好(可能是个 bridge,1.1)、按 proto 配地址(static 就 ip addr add、dhcp 就跑 DHCP 客户端)、装上相应路由(1.2)。
  • 换句话说:你写"我要一个叫 lan 的接口,静态 IP 192.168.1.1/24,基于 br-lan",netifd 就替你执行 1.1 + 1.2 的一串命令。

proto(协议)是 netifd 的精髓:同一个接口配置,proto 决定它怎么拿到地址——static(写死)、dhcp(netifd 起 DHCP 客户端去问,WAN 常用)、pppoe(触发 pppd 拨号,2.6)。每种 proto 是 netifd 的一个协议处理器插件。

路由器关联 router-link

"逻辑接口 vs device"是新手最容易懵的地方,但对上 1.1 就通了:device 是"网卡 / 桥 / vlan 这类二层实体"(ip link 那层),interface 是"在它之上的一套三层身份(IP + proto + 路由)"。LAN 多个物理口 → 一个 br-lan device → 一个 lan interface——这条链把 0.2 / 1.1 的桥接和这里的接口配置串了起来。

4从改配置到生效:完整数据流

一次典型的"改 LAN 网段"是这样走完的:

  1. 改 UCI:uci set network.lan.ipaddr='192.168.2.1'; uci commit network(或 LuCI 点一点)。此时 /etc/config/network 变了,但内核里的接口还是老 IP。
  2. 通知生效:/etc/init.d/network reload。这经 procd 触发 netifd 重新读配置。
  3. netifd 执行:比对新旧配置,把 lan 接口地址从旧改成新——底层就是 Phase 1 的 ip addr / ip route
  4. 生效:内核里的接口更新,新网段开始工作(你的电脑可能要重新 DHCP 拿新网段地址——又回到 dnsmasq)。

LuCI 网页改配置其实是同一条链的自动化:你点"保存并应用" → rpcd 经 ubus 把改动写进 UCI 并触发对应服务 reload → netifd / fw4 重读生效。所以网页操作和命令行 uci + reload,底层完全等价

"我改了 /etc/config 怎么没用?"

"改配置"和"生效"是特意分开的两步:UCI 是持久配置(重启后仍在),reload / restart 才把它应用到运行中的系统。好处是能一次改好多项再统一 reload,也明确区分"配置状态"与"运行状态"。新手最常见的坑就是改了 UCI 却忘了 reload。

路由器关联 router-link

于是 2.1 那句"UCI → netifd / fw4 → 内核,ubus 串起来、procd 管进程",在这章被填满了:UCI 是单一配置源(§2),netifd 等把它翻译成 Phase 1 的内核状态(§3),改动经 procd 触发 reload、经 ubus 协调(§4)。后面几章(2.3 dnsmasq、2.4 fw4、2.5 hostapd、2.6 WAN)都是"某个具体子系统的 UCI 长什么样、对应进程怎么把它落地"——全在这个框架里。

本章小结

  • OpenWRT = 三层:UCI(统一配置)→ 守护进程(翻译成行为)→ 内核 / 服务;LuCI 只是配置层的图形前端。
  • UCI:所有配置统一格式(config / option / list)、集中在 /etc/config/、用 uci set/get/commit 管;是"单一真相来源"。
  • netifd 读 network 配置,把"逻辑接口(interface,带 proto/IP)"落成 Phase 1 的真实 device + 地址 + 路由;proto(static/dhcp/pppoe)决定怎么拿配置。
  • 生效两步:改 UCI(持久)→ reload/restart(应用);经 procd 触发、netifd 等重读、内核更新。"改了没用"多半是没 reload。
  • LuCI 网页操作 = rpcd + ubus 改 UCI + 触发 reload,与命令行等价;这套框架贯穿 Phase 2 后面每一章。

动手练习

  1. 若有 OpenWRT:uci show network 看结构,找出 lan 的 config interface 段;cat /etc/config/network 对照,认出 config / option / list 三种关键词。
  2. 用 uci 改一个无关紧要的值(如某接口注释、一个 list 项),uci commitcat 确认文件变了;再 uci revert 改回。(别在远程 SSH 时改 lan 的 IP,可能把自己踢下线。)
  3. 思考题:为什么"改了 /etc/config/network 但网络没变"?补上哪一步才生效?(reload。)
  4. 进阶:画出"在 LuCI 里把 LAN IP 从 .1 改到 .2 并应用"的完整数据流,标出每步组件(浏览器 → uhttpd → rpcd → ubus → UCI 文件 → procd → netifd → 内核 ip addr),和第 4 节命令行版对照。